import { Transaction } from "tiny-entity2";
import { IQueryObject } from "tiny-entity2/queryObject";
import { ApiDataContext } from "../domain/apiDataContext";
import { AccountPermits } from "../domain/models/accountPermits";
import { AccountRoles } from "../domain/models/accountRoles";
import { Department } from "../domain/models/department";
import { Organization } from "../domain/models/organization";
import { OrganizationTree } from "../domain/models/organizationTree";
import { Role } from "../domain/models/role";
import { User } from "../domain/models/user";
import { BaseService } from "./baseService";

export class OrganizationTreeService extends BaseService {
    async CreateorganizationTree(entity: OrganizationTree, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let d = new OrganizationTree();
            d.ConverToEntity(entity);
            return ctx.Create(d);
        });
    }
    async UpdateorganizationTree(entity: OrganizationTree, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let d = new OrganizationTree();
            d.ConverToEntity(entity);
            return ctx.Update(d);
        });
    }
    async DeleteOrganizationTree(entity: OrganizationTree, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let d = new OrganizationTree();
            d.ConverToEntity(entity);
            // ctx.Delete<OrganizationTree>(x=>x.name == $args1, ctx.User,  {$args1: 'ddddd'});
            return ctx.Delete(d);
        });
    }
    async DeleteOrganizationTreeById(id: string, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let d = await ctx.OrganizationTree.First(x => x.id == $args1, { $args1: id });
            d.isDelete = true;
            let result = {};

            if (d.objectName == Department.name) {
                let obj: Department = await ctx[d.objectName].First(x => x.id == $args1, { $args1: d.objectId });
                if (obj) {
                    obj.isDelete = true;
                    ctx.Update(obj);
                }
            }
            else if (d.objectName == User.name) {
                let obj: User = await ctx[d.objectName].First(x => x.id == $args1, { $args1: d.objectId });
                if (obj) {
                    obj.isDelete = true;
                    ctx.Update(obj);
                }
            }
            else if (d.objectName == Organization.name) {
                let obj: Organization = await ctx[d.objectName].First(x => x.id == $args1, { $args1: d.objectId });
                if (obj) {
                    obj.isDelete = true;
                    ctx.Update(obj);
                }
            }
            result = ctx.Update(d);

            let rp = await this.QueryOrganizationTree({ parentId: id });

            if (rp && rp.length > 0) {
                rp.forEach(async x => {
                    await this.DeleteOrganizationTreeById(x.id);
                });
            }
        });
    }
    async DeleteOrganizationTreeByObjectId(objectId: string, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            return ctx.Delete<OrganizationTree>(x => x.objectId == $args1, ctx.OrganizationTree, { $args1: objectId });
        })
    }

    async GetOrganizationTreeById(id: string) {
        let ctx = new ApiDataContext();
        let r = await ctx.OrganizationTree.First(x => x.id == $args1, { $args1: id });

        if (r) {
            r.object = await ctx[r.objectName].First(x => x.id == $args1, { $args1: r.objectId });

            if (r.objectName == Department.name) {
                if (r.object) {
                    let leaderPerson: string = r.object["leaderPerson"];
                    if (leaderPerson && leaderPerson.length > 0) {
                        r.object["leaderObj"] = await ctx[User.name].First(x => x.id == $args1, { $args1: leaderPerson });
                    }
                }
            }
            else if (r.objectName == User.name) {
                if (r.object) {
                    let accountId: string = r.object["accountId"];
                    r.object["roles"] = [];
                    if (accountId && accountId.length > 0) {
                        let qar = ctx.AccountRoles as IQueryObject<AccountRoles>;
                        qar.Where(x => x.accountId == $args1, { $args1: accountId });
                        let accRoles = await qar.ToList();
                        if (accRoles && accRoles.length > 0) {
                            let roleids: string[] = [];
                            accRoles.forEach(x => {
                                roleids.push(x.roleId);
                            });
                            if (roleids && roleids.length > 0) {
                                let roledb = ctx.Role as IQueryObject<Role>;

                                roledb = roledb.Contains(x => x.id, roleids) as IQueryObject<Role>;

                                r.object["roles"] = await roledb.ToList();
                            }
                        }
                    }
                }
            }

            let q = ctx.AccountPermits as IQueryObject<AccountPermits>;

            q.Where(x => x.authObjectId == $args1, { $args1: r.objectName == Department.name ? r.objectId : (r.objectName == User.name && r.object ? r.object["accountId"] : "") });

            r.accountpermits = await q.ToList();

            let rp = await ctx.OrganizationTree.First(x => x.id == $args1, { $args1: r.parentId });
            if (rp) {
                r.parentObject = await ctx[rp.objectName].First(x => x.id == $args1, { $args1: rp.objectId });
            }
        }

        return r;
    }
    async QueryOrganizationTree(params: {
        organizationId?: string;
        objectName?: string | string[];
        objectId?: string;
        parentId?: string;
        objectIds?: string[];
        ids?: string[];
    }) {
        let ctx = new ApiDataContext();
        let q = ctx.OrganizationTree as IQueryObject<OrganizationTree>;
        q = q.Where(x => x.isDelete == $args1, { $args1: false });
        if (params) {
            if (params.organizationId) {
                q = q.Where(x => x.organizationId == $args1, { $args1: params.organizationId });
            }
            if (params.objectName) {
                if (params.objectName instanceof Array) {
                    q = q.Contains(x => x.objectName, params.objectName) as IQueryObject<OrganizationTree>;
                }
                else {
                    q = q.Where(x => x.objectName == $args1, { $args1: params.objectName });
                }
            }
            if (params.objectId) {
                q = q.Where(x => x.objectId == $args1, { $args1: params.objectId });
            }
            if (params.parentId) {
                q = q.Where(x => x.parentId == $args1, { $args1: params.parentId });
            }
            if (params.objectIds && params.objectIds.length > 0) {
                q = q.Contains(x => x.objectId, params.objectIds) as IQueryObject<OrganizationTree>;
            }
            if (params.ids && params.ids.length > 0) {
                q = q.Contains(x => x.id, params.ids) as IQueryObject<OrganizationTree>;
            }
        }
        let list = await q.ToList();
        for (let item of list) {
            item.object = await ctx[item.objectName].First(x => x.id == $args1, { $args1: item.objectId });
        }

        return list;
    }

    GetOrgTreeNodeByObjectId(objectId: string) {
        let ctx = new ApiDataContext();
        return ctx.OrganizationTree.First(x => x.objectId == $args1, { $args1: objectId });
    }
}

export function checkIsChildDep(data: OrganizationTree[], currNodeId: string, checkNodeId: string, callBack: Function): any {
    data.forEach(x => {
        if (x.parentId == currNodeId) {
            if (x.id == checkNodeId) {
                callBack(true);
            }
            else {
                return checkIsChildDep(data, x.id, checkNodeId, callBack);
            }
        }
    });
}